#ifndef WEAPONS_H
#define WEAPONS_H

//Weapons that offer continuous fire by holding down the mouse key. Has a cartridge. No overheating. 
class Inventory_Gun
{
 public:
 Player* Owner;
 char* Description;
 Conventional_Projectile* Bullets; int Mem_Size;
 hgeSprite* GunSprite; hgeSprite* Cartridge; hgeSprite* BulletSprite; hgeSprite* Casing;
 hgeParticleSystem* MuzzleFlash;
 string weapon_name; float weapon_weight; int ammo_count, shells_per_shot, cur_ammo; float spread_factor, base_reload, cur_reload;
 int fire_type; float fire_rate, fire_time; //0 for semi-automatic, 1 for automatic, 2 for burst-fire, 3 for infinite with cool-down
 float  muzzle_radius; //Distance away from the player that the bullet should generate.
 float  base_damage, bullet_caliber; //The base damage of the bullet plus the size
 float  base_velocity, base_acceleration, velocity_damage_factor, armor_piercing_factor;
 bool   affected_by_player_movement;
 float  base_accuracy, cur_accuracy, speed_bink_factor, accuracy_dropoff, accuracy_gain;
 float  bullet_dropoff_time, velocity_dropoff; 
 bool  Is_Bouncy,  Is_Flaming,  Is_Poison,   Is_Paralysis, Is_Ionic, Is_Piercing;
 short Bounce_Num,  Flame_DPS, Poison_DPS, Paralysis_Time, Ion_Dist,  Pierce_Num;
 //Secondary weapon functions
 //Secondary* Function //Attaching a secondary function to the gun.
 //Control Functions
 Inventory_Gun();
 Inventory_Gun(Inventory_Gun* Base_Gun);
 Inventory_Gun(Player* Gun_Owner, Inventory_Gun* Base_Gun); 
 void Fire(); void Secondary(Inventory_Gun* SecondGun);  void Reload(); void Drop(); void Render(); void Update(float delta_time);
};

Inventory_Gun::Inventory_Gun() {}                         //Creates a blank weapon
Inventory_Gun::Inventory_Gun(Inventory_Gun* Base_Gun) {}  //Creates a weapon with established parameters (missing owner)
Inventory_Gun::Inventory_Gun(Player* Gun_Owner, Inventory_Gun* Base_Gun)    //Creates a weapon containing an owner (deep copy)
{
 Owner = Gun_Owner;
 weapon_name                 = Base_Gun->weapon_name;
 GunSprite                   = Base_Gun->GunSprite;
 BulletSprite                = Base_Gun->BulletSprite;
 Casing                      = Base_Gun->Casing;
 Cartridge                   = Base_Gun->Cartridge;
 weapon_weight               = Base_Gun->weapon_weight;
 ammo_count                  = Base_Gun->ammo_count;
 cur_ammo                    = Base_Gun->cur_ammo;
 shells_per_shot             = Base_Gun->shells_per_shot;
 spread_factor               = Base_Gun->spread_factor;
 base_reload                 = Base_Gun->base_reload;
 fire_type                   = Base_Gun->fire_type;
 fire_rate                   = Base_Gun->fire_rate;
 muzzle_radius               = Base_Gun->muzzle_radius;
 base_damage                 = Base_Gun->base_damage;
 bullet_caliber              = Base_Gun->bullet_caliber;
 base_velocity               = Base_Gun->base_velocity;
 base_acceleration           = Base_Gun->base_acceleration;
 velocity_damage_factor      = Base_Gun->velocity_damage_factor;
 armor_piercing_factor       = Base_Gun->armor_piercing_factor;
 affected_by_player_movement = Base_Gun->affected_by_player_movement;
 base_accuracy               = Base_Gun->base_accuracy;
 speed_bink_factor           = Base_Gun->speed_bink_factor;
 accuracy_dropoff            = Base_Gun->accuracy_dropoff;
 accuracy_gain               = Base_Gun->accuracy_gain;
 bullet_dropoff_time         = Base_Gun->bullet_dropoff_time;
 velocity_dropoff            = Base_Gun->velocity_dropoff;
 Is_Bouncy      = Base_Gun->Is_Bouncy;      Is_Flaming = Base_Gun->Is_Flaming;  Is_Poison   = Base_Gun->Is_Poison;
 Is_Paralysis   = Base_Gun->Is_Paralysis;   Is_Ionic   = Base_Gun->Is_Ionic;    Is_Piercing = Base_Gun->Is_Piercing;
 Bounce_Num     = Base_Gun->Bounce_Num;     Flame_DPS  = Base_Gun->Flame_DPS;   Poison_DPS  = Base_Gun->Poison_DPS;
 Paralysis_Time = Base_Gun->Paralysis_Time; Ion_Dist   = Base_Gun->Ion_Dist;    Pierce_Num  = Base_Gun->Pierce_Num;
 //Finally, we allot a bullet amount to this weapon. This allotment is optimized by alloting the maximum amount
 //of bullets this weapon can fire plus some additional space for buffs.
 Mem_Size = static_cast<int>(bullet_dropoff_time/fire_rate) + 10;
 Bullets = new Conventional_Projectile[Mem_Size];
 fire_time = 0;  //Gun is ready to fire.
 cur_reload = 0; //Gun is reloaded.
 cur_ammo = ammo_count; //Gun is fully loaded.
 cur_accuracy = base_accuracy; //The gun is as accurate as possible
}

void Inventory_Gun::Fire()                                                  //Fires the weapon once
{
 if(fire_time <= 0 && cur_reload <= 0 && cur_ammo > 0)//Creates a bullet if the fire time allows.
  {
   for(int i = 0; i < Mem_Size; i++)
   {
    if(!Bullets[i].Active_Projectile) //Finds the first bullet space that is open.
     {
      float calc_inacc = (cur_accuracy*M_PI)/180;
      float inaccuracy = hge->Random_Float(-calc_inacc, calc_inacc);
      Bullets[i].Active_Projectile = true;
      Bullets[i].Position_X     = Owner->X_Position + muzzle_radius*cos(Owner->Angle);
      Bullets[i].Position_Y     = Owner->Y_Position + muzzle_radius*sin(Owner->Angle);
      Bullets[i].Velocity_X     = (Owner->X_Velocity + base_velocity)*cos(Owner->Angle + inaccuracy);
      Bullets[i].Velocity_Y     = (Owner->Y_Velocity + base_velocity)*sin(Owner->Angle + inaccuracy);      
      Bullets[i].Acceleration_X = (base_acceleration)*cos(Owner->Angle);
      Bullets[i].Acceleration_Y = (base_acceleration)*sin(Owner->Angle);
      Bullets[i].life_time      = bullet_dropoff_time;
      i = Mem_Size; //End search
      fire_time = fire_rate; //Prevent firing until later.
      cur_ammo--; //Subtract a bullet
      cur_accuracy = cur_accuracy + accuracy_dropoff; //Increase inaccuracy
      if(cur_ammo <= 0) //Time for reload
       {
        cur_reload = base_reload;
        //Finally, some post process effects to add the cartridge to the prop layer.
        for(int i = 0; i < max_action_prop; i++)
         {
         if(!Action_Props[i].in_use) //If the memory space is open
          {
           float shell_scatter = hge->Random_Float(-M_PI/8, M_PI/8); //Denotes the scattering of shells when ejected out of chamber
           float exit_speed    = hge->Random_Float(55, 100);         //Randomizes the speed of exit
           Action_Props[i].Create(Cartridge, Owner->X_Position + 12*cos(Owner->Angle), Owner->Y_Position + 12*sin(Owner->Angle), exit_speed*cos(Owner->Angle + M_PI/2 + shell_scatter), exit_speed*sin(Owner->Angle + M_PI/2 + shell_scatter), 0, 0, hge->Random_Float(100, 200), Owner->Angle, .5, true);
           i = max_action_prop; //End loop
          }
         }           
       }
     }    
   } 
   //Finally, some post process effects
   for(int i = 0; i < max_action_prop; i++)
   {
    if(!Action_Props[i].in_use) //If the memory space is open
     {
      float shell_scatter = hge->Random_Float(-M_PI/8, M_PI/8); //Denotes the scattering of shells when ejected out of chamber
      float exit_speed    = hge->Random_Float(35, 100);         //Randomizes the speed of exit
      Action_Props[i].Create(Casing, Owner->X_Position + muzzle_radius/2*cos(Owner->Angle), Owner->Y_Position + muzzle_radius/2*sin(Owner->Angle), exit_speed*cos(Owner->Angle + M_PI/2 + shell_scatter), exit_speed*sin(Owner->Angle + M_PI/2 + shell_scatter), 0, 0, hge->Random_Float(300, 600), Owner->Angle, .5, true);
      i = max_action_prop; //End loop
     }
   }
  }
}

void Inventory_Gun::Secondary(Inventory_Gun* SecondGun)                                             //Secondary weapon feature
{
 //Essentially, this function calls another gun and fires THAT in place of the original weapon.                                                                      
}

void Inventory_Gun::Reload()                                                //Reloads the weapon
{
 if(cur_ammo != ammo_count) //Perform reload.
  {
   cur_ammo = 0;
   cur_reload = base_reload;
  }
} 

void Inventory_Gun::Drop()                                                  //Drops the weapons and create a pickupable item
{
                                       
}

void Inventory_Gun::Render()                                                //Renders the position of all bullets                                              
{
 //Render Gun and Cartridge
 GunSprite->RenderEx(Owner->X_Position - Camera_X + 20*cos(Owner->Angle) + Screen_Width/2, Owner->Y_Position - Camera_Y + Screen_Height/2 + 20*sin(Owner->Angle), Owner->Angle); 
 if(cur_ammo != 0 && cur_reload <= 0) Cartridge->RenderEx(Owner->X_Position - Camera_X + 12*cos(Owner->Angle) + Screen_Width/2, Owner->Y_Position - Camera_Y + Screen_Height/2 + 12*sin(Owner->Angle), Owner->Angle); 
 for(int i = 0; i < Mem_Size; i++)
  {
   if(Bullets[i].Active_Projectile)
   {
    //We first have to figure out the rotation of the bullet through it's velocity vector
    float Angle = FaceRotation(0, 0, Bullets[i].Velocity_X, Bullets[i].Velocity_Y);
    BulletSprite->RenderEx(Bullets[i].Position_X  - Camera_X + Screen_Width/2, Bullets[i].Position_Y - Camera_Y + Screen_Height/2, Angle);
   }
  }
}

void Inventory_Gun::Update(float delta_time)                                                //Updates the position of all active bullets
{
 if(fire_time  > 0) fire_time  = fire_time  - delta_time;
 if(cur_reload > 0) //Reload mechanism
  {
   cur_reload = cur_reload - delta_time;
   if(cur_reload <= 0) 
    {
     cur_ammo = ammo_count;    
    }
  }
 if(cur_accuracy > base_accuracy)  cur_accuracy = cur_accuracy - accuracy_gain*delta_time;
 if(cur_accuracy <= base_accuracy) cur_accuracy = base_accuracy;
 for(int i = 0; i < Mem_Size; i++)  //Updates bullet information and garbage collection
  {
   if(Bullets[i].Active_Projectile) //If the bullet is working
    {
     Bullets[i].life_time = Bullets[i].life_time - delta_time;
     //Update positional data of the bullets
     //Equation: D = vi*t + .5*a*t^2
     Bullets[i].Position_X = Bullets[i].Position_X + (Bullets[i].Velocity_X*delta_time) + (.5*Bullets[i].Acceleration_X*delta_time*delta_time);
     Bullets[i].Position_Y = Bullets[i].Position_Y + (Bullets[i].Velocity_Y*delta_time) + (.5*Bullets[i].Acceleration_Y*delta_time*delta_time);
     //Equation: Vf = Vi + a*t
     Bullets[i].Velocity_X = Bullets[i].Velocity_X + Bullets[i].Acceleration_X*delta_time;
     Bullets[i].Velocity_Y = Bullets[i].Velocity_Y + Bullets[i].Acceleration_Y*delta_time;
     if(Bullets[i].life_time < 0) Bullets[i].Active_Projectile = false; //If the bullet has gone through lifetime, then destroy it.
    }
  }
 
}

//----------------------------------------------------------------------------------------

class Inventory_Arty
{
 
};

class Inventory_Melee
{
      
};

class Inventory_Equip
{
      
};

class Stationary_Gun
{
      
};

class Stationary_Arty
{
      
};

#endif
